#ifndef GAMEWORLD_H
#define GAMEWORLD_H

#include <SFML/Network.hpp>

#include <map>
#include <stack>
#include "gameobject.h"
#include "gameworldeventlistener.h"

class DLL_EXPORT GameWorld
{
	public:
		GameWorld(bool confirmedStepsOnly, GameworldEventListener* listener);
		void SynchronizeFromWorld(GameWorld& other);

		virtual ~GameWorld();

		// Someone has determined that this package
		bool HandleChanges(sf::Uint8 type, sf::Packet& remainder);
		bool Step();

		bool InsertObject(GameObject& object); ///< special insertion method, because on the client we must besure that the objects have the same id as on the server... perhaps a translation table would be better.

		sf::Uint32 CreateShip(sf::Vector2f pos);
		sf::Uint32 CreateObject(sf::Uint8 type, sf::Vector2f pos);
		sf::Uint32 CreateObject(sf::Uint32 id, sf::Uint8 type, sf::Vector2f pos);

		bool DeleteObject(sf::Uint32 ID);
		GameObject* GetObject(sf::Uint32 ID);

		void UpdateShipControls(GameObject& object, sf::Uint8 newControls);
		sf::Uint32 worldTime;

		// This could perhaps be done in a more nice way.
		// Right now we handle the entire responsibily of the universe to all crazy kinda erhm.. something.
		GameObjectMap GetAllObjects();

	protected:
		GameObjectMap allObjects;

		GameObjectMap ships;
		GameObjectMap planets;
		GameObjectMap weapons;
		GameObjectList bullets;

	private:
		// Creates an object, prefereable taking preallocated from objectStore
		GameObject* CreateObject(sf::Uint32 id);

		// inactive object
		std::stack<GameObject*> objectStore;
		sf::Uint32 nextObjectID;
		bool confirmedStepsOnly;

		void UpdateShip(GameObject& ship);
		void ApplyGravity(GameObject& planet, GameObject& ship);
		void ResolveObjectPlanetCollision(GameObject& planet, GameObject& ship);
		float ObjectDistSQ(GameObject& obj1, GameObject& obj2, bool& OUTcollides);
		void ReleaseWeapons(GameObject& ship);

		GameworldEventListener* gameworldEventListener;
		void OnObjectCreated(GameObject& object);
		void OnObjectDeleted(GameObject& object);
		void OnShipKilled(GameObject& object);
		void OnShipControlChanged(GameObject& object);

};

#endif // GAMEWORLD_H
